/**
  ******************************************************************************
  * @文件     tpad.c
  * @作者     hero_cao
  * @版本     V1.0.0
  * @日期     2025/06/15
  * @概要     tpad驱动
  ******************************************************************************
  */
  
/* Includes ------------------------------------------------------------------*/
#include "./board/bsp.h"
#include "./tpad/tpad.h"


/* Private variables ---------------------------------------------------------*/
volatile uint16_t g_tpad_default_val = 0;		/* 空载的时候(没有手按下),计数器需要的时间（这个值应该在每次开机的时候被初始化一次） */

/* Private functions ---------------------------------------------------------*/
static void tpad_reset(void);                   /* 复位 */
static uint16_t tpad_get_val(void);             /* 得到定时器捕获值 */
static uint16_t tpad_get_maxval(uint8_t n);     /* 读取n次, 获取最大值 */


/**
 * @brief       初始化触摸按键
 * @param       psc-分频系数(值越小, 越灵敏, 最小值为: 1)
 * @retval      0, 初始化成功; 1, 初始化失败;
 */
uint8_t tpad_init(uint16_t psc)
{
    uint16_t buf[10];
    uint16_t temp;
    uint8_t j, i;
    
    gpio_init_type gpio_init_struct;
	tmr_input_config_type  tmr_input_struct;

	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_TMR5_PERIPH_CLOCK, TRUE);
	
	gpio_default_para_init(&gpio_init_struct);
	
	/* configure the CH2 pin */
	gpio_init_struct.gpio_pins = GPIO_PINS_1;
	gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
	gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init(GPIOA, &gpio_init_struct);
	
	/* configure counter settings */
	tmr_cnt_dir_set(TMR5, TMR_COUNT_UP);
	tmr_clock_source_div_set(TMR5, TMR_CLOCK_DIV1);
	tmr_period_buffer_enable(TMR5, FALSE);
	tmr_base_init(TMR5, 65535, (psc - 1));
	
	/* configure primary mode settings */
	tmr_sub_sync_mode_set(TMR5, FALSE);
	tmr_primary_mode_select(TMR5, TMR_PRIMARY_SEL_RESET);
	
	/* configure channel 2 input settings */
	tmr_input_struct.input_channel_select = TMR_SELECT_CHANNEL_2;
	tmr_input_struct.input_mapped_select = TMR_CC_CHANNEL_MAPPED_DIRECT;
	tmr_input_struct.input_polarity_select = TMR_INPUT_RISING_EDGE;
	tmr_input_struct.input_filter_value = 0;
	tmr_input_channel_init(TMR5, &tmr_input_struct, TMR_CHANNEL_INPUT_DIV_1);

	tmr_counter_enable(TMR5, TRUE);

    for (i = 0; i < 10; i++) {
        buf[i] = tpad_get_val();
		Delay_ms(10);
    }

    for (i = 0; i < 9; i++) {
        for (j = i + 1; j < 10; j++) {
            if (buf[i] > buf[j]) {
                temp = buf[i];
                buf[i] = buf[j];
                buf[j] = temp;
            }
        }
    }

    temp = 0;

    for (i = 2; i < 8; i++) {
        temp += buf[i];
    }
    
    g_tpad_default_val = temp / 6;

    if (g_tpad_default_val > (uint16_t)TPAD_ARR_MAX_VAL / 2) {
        return 1;		/* 初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常! */
    }

    return 0;
}

/**
 * @brief       扫描触摸按键
 * @param       mode ：扫描模式
 *   @arg       0, 不支持连续触发(按下一次必须松开才能按下一次);
 *   @arg       1, 支持连续触发(可以一直按下)
 * @retval      0, 没有按下; 1, 有按下;
 */
uint8_t tpad_scan(uint8_t mode)
{
    static uint8_t keyen = 0;       /* 0, 可以开始检测;  > 0, 还不能开始检测; */
    uint8_t res = 0;
    uint8_t sample = 3;             /* 默认采样次数为3次 */
    uint16_t rval;

    if (mode) {
        sample = 6;                 /* 支持连按的时候，设置采样次数为6次 */
        keyen = 0;                  /* 支持连按, 每次调用该函数都可以检测 */
    }

    rval = tpad_get_maxval(sample);
    
    if (rval > (g_tpad_default_val + TPAD_GATE_VAL)){    /* 大于tpad_default_val + TPAD_GATE_VAL,有效 */
        if (keyen == 0) {
            res = 1;                /* keyen==0, 有效 */
        }
		
        keyen = 3;                  /* 至少要再过3次之后才能按键有效 */
    }

    if (keyen)keyen--;

    return res;
}

/**
 * @brief       复位TPAD
 *   @note      我们将TPAD按键看做是一个电容, 当手指按下/不按下时容值有变化
 *              该函数将GPIO设置成推挽输出, 然后输出0, 进行放电, 然后再设置
 *              GPIO为浮空输入, 等待外部大电阻慢慢充电
 * @param       无
 * @retval      无
 */
static void tpad_reset(void)
{
    gpio_init_type gpio_initstructure;
	
	/* GPIO clock enable */
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	
	gpio_default_para_init(&gpio_initstructure);
	
	gpio_initstructure.gpio_pins = GPIO_PINS_1;
	gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
	gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_initstructure.gpio_pull = GPIO_PULL_DOWN;
	gpio_init(GPIOA, &gpio_initstructure);

    gpio_bits_reset(GPIOA, GPIO_PINS_1);				/* TPAD引脚输出0, 放电 */
	
	tmr_counter_value_set(TMR5, 0);						//计数器清0
	tmr_flag_clear(TMR5, TMR_C2_FLAG | TMR_OVF_FLAG);	//清除中断标志

    gpio_initstructure.gpio_pins = GPIO_PINS_1;
	gpio_initstructure.gpio_mode = GPIO_MODE_INPUT;
    gpio_initstructure.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_initstructure);        
}

/**
 * @brief       得到定时器捕获值
 *   @note      如果超时, 则直接返回定时器的计数值
 *              我们定义超时时间为: TPAD_ARR_MAX_VAL - 500
 * @param       无
 * @retval      捕获值/计数值（超时的情况下返回）
 */
static uint16_t tpad_get_val(void)
{
    tpad_reset();
    
    while (tmr_flag_get(TMR5, TMR_C2_FLAG) == RESET) {		/* 等待通道CHY捕获上升沿 */
    
        if (tmr_counter_value_get(TMR5) > TPAD_ARR_MAX_VAL - 500) {
            return tmr_counter_value_get(TMR5);				/* 超时了,直接返回CNT的值 */
        }
    }

    return TMR5->c2dt;                                      /* 返回捕获/比较值 */
}

/**
 * @brief       读取n次, 取最大值
 * @param       n       ：连续获取的次数
 * @retval      n次读数里面读到的最大读数值
 */
static uint16_t tpad_get_maxval(uint8_t n)
{
    uint16_t temp = 0;
    uint16_t maxval = 0;

    while(n--) {
        temp = tpad_get_val();  /* 得到一次值 */

        if (temp > maxval){
            maxval = temp;
        }
    }

    return maxval;
}

